package com.charlotte.study.gupao.singleton.lazy;

/**
 * 懒汉式单例，双重检查模式
 * 优点：
 *      1. 线程安全（加了锁）
 * 缺点：
 *      1. 逻辑复杂
 * @author junjie.ding
 * @date 2020/2/27
 */
public class LazyDoubleCheckSingletonDemo {

    // volatile是为了防止创建对象的过程中的指令的重排序
    private volatile static LazyDoubleCheckSingletonDemo demo = null;

    private LazyDoubleCheckSingletonDemo() {}

    public static LazyDoubleCheckSingletonDemo getInstance(){
        // 第一次检查是否要阻塞
        if(demo == null){
            synchronized (LazyDoubleCheckSingletonDemo.class){
                // 第二次检查是否需要重新创建实例
                if(demo == null){
                    // 位置1
                    /**
                     * 该过程涉及多个过程
                     * 1、给new LazyDoubleCheckSingletonDemo();分配内存地址
                     * 2、给demo分配内存地址
                     * 3、将demo指向new LazyDoubleCheckSingletonDemo()的内存地址
                     * 4、初次访问对象
                     *
                     * 如果不在demo这个变量上设为volatile，jvm底层会出现指令重排序
                     * 例如：线程T1已经执行完创建过程，但这时候仅仅是将demo指向了一个空的内存地址，没有具体内容，demo仍为空，但线程认为已经执行完毕，释放锁，
                     *      这时当线程T2抢到锁，判断demo == null成立，又会重新创建对象，造成线程不安全。所以需要volatile来禁止指令重排序
                     */
                    demo = new LazyDoubleCheckSingletonDemo();
                }
            }
        }
        return demo;
    }
}
